Das Hilfethema Datentypen unterscheidet einfache Datentypen wie Ganzzahlen, Gleitkommazahlen und Wahrheitswerte sowie zusammengesetzte Datentypen, die sich aus mehreren Werten einfacher Datentypen zusammensetzen. Die nächsten Kapitel führen die zusammengesetzten Datentypen Satz (engl. Type) und Datenfeld (engl. array) ein.
Ein Satz ist eine Struktur aus gleichen oder verschiedenen Datentypen. Der folgende Satz setzt sich zum Beispiel aus verschiedenen numerischen und symbolischen Elementen zusammen. Man nennt deshalb einen solchen Datentyp heterogen zusammengesetzt.
137221
Fritz Meier
Bahnhofstrasse 25
9000 St. Gallen
071/223 90 85
01.8.98
Die entsprechende Vereinbarung eines Datentyps Mitarbeiter lautet:
Type Mitarbeiter Personalnummer As Integer Name As String Strasse As String Ort As String Telefon As Long Einstellungsdatum As Date End Type
Heterorgene Datentypen spielen in den Zeilen von Datenbank-Tabellen eine wichtige Rolle. Im folgenden beschäftigen wir uns nur mit einem homogen zusammengesetzten Datentyp, dem Datenfeld (engl. array). Eine Konstante des Typs Datenfeld besteht aus beliebig vielen Werten des gleichen Datentyps. Im folgenden Beispiel besteht die Datenfeld-Konstante Punktetotale aus den Punktetotalen von fünf Fussballmannschaften:
|
22 |
16 |
28 |
6 |
32 |
Oft setzt man die Elemente einer Datenfeld-Konstante zwischen eckige Klammern: [22, 16, 28, 6, 32]. Eine Datenfeld-Variable ist eine Folge von Zellen des gleichen Datentyps, auf die unter dem gleichen Namen, aber verschiedenen Indizes - zum Beispiel 1 bis 5 - zugegriffen werden kann. Meist ändert sich die Grösse eines Datenfelds während des Programms nicht. Wir definieren deshalb für jedes Datenfeld eine untere und eine obere Grenze, welche den Wertebereich des Index begrenzen:
| Name | Läufer(1) | Läufer(2) | Läufer(3) | Läufer(4) | Läufer(5) |
| Inhalt | Anna | Bruno | Dora | Franz | Karin |
Name der Datenfeldvariable: Läufer
Grösse (Dimension): 5
Untergrenze:
1
Obergrenze:
5
Der Datenfeldname und der Index kennzeichnen jedes Element eindeutig. Läufer(2) bezeichnet zum Beispiel den zweiten Läufer. Jede Zelle des Datenfelds gehört dem gleichen Datentyp an. Der Array Läufer kann zum Beispiel nur Werte des Datentyps String enthalten. Ein Datenfeld hat den Vorteil, dass es sowohl ganz als auch elementweise verarbeitet werden kann. Die Indizierung erlaubt ausserdem die einfache Verarbeitung aller Elemente in einer Schleife.
Das Datenfeld Läufer wird wie folgt vereinbart:
Dim Läufer ( 1 To 5 ) As String.
Allgemeiner lautet die Syntax einer Datenfeld-Vereinbarung:
Dim <Datenfeldname> ( <Untergrenze> To <Obergrenze> ) As <Datentyp>.
Statt Dim kann auch Private oder Public stehen (siehe Fallbeispiel Gewinnverteilung). Der Zugriff auf ein Datenfeld ist einfach. Die folgende Anweisung liest den Inhalt der fünften Zelle von Läufer und weist ihn der Variablen Tmp zu:
Dim Tmp As String Tmp = Läufer(5).
Ebenso einfach ist die Änderung eines Zellinhalts. Die folgende Anweisung ersetzt den Inhalt der fünften Zelle durch Pauline:
Läufer(5) = "Pauline".
Die Indizierung erlaubt die einfache Zusammenfassung mehrerer Lese- oder Schreiboperationen: Die folgende Zählschleife weist zum Beispiel allen Zellen den Inhalt Fritz zu:
Dim Läufer(1 To 5) As String Dim i As IntegerFor i = 1 To 5 Läufer(i) = “Fritz” Next i
Die Zählschleife eignet sich besonders gut für das Durchlaufen eines Datenfelds. Verglichen mit der bereits eingeführten Schleife mit Ausführungsbedingung (While) erspart sie der Programmiererin die explizite Initialisierung, Prüfung und Erhöhung einer Indexvariable.
Die Syntax der Zählschleife lässt sich verallgemeinern:
Dim Index As Integer
For Index = <Untergrenze> To <Obergrenze>
<Anweisungen>
Next
Wer im Telefonbuch sucht, kann drei Strategien einsetzen:
Die folgende Tabelle fasst die drei Suchstrategien zusammen und nennt ihre Vor- und Nachteile. Eine schnelle Suchstrategie stellt grössere Anforderungen an die Organisation der Daten und an das Vorwissen des Benutzers:
| Suche | Suchbeispiel | Bedingung | Effizienz |
| direkt | Seite 143 | Seiten nummeriert | sehr schnell |
| sequentiell | 061 / 422 13 07 | keine | langsam |
| binär | Bohnenblust Fritz | Einträge sortiert | schnell |
Ein konventionelles Telefonbuch ist gleich wie ein Datenfeld organisiert. Eine Seite entspricht einer Zelle, und eine Seitennummer entspricht dem Zellenindex. Wir bilden deshalb die drei Suchstrategien auf unser Datenfeld Läufer ab.
Direkt suchen heisst mit einem gegebenen Index ein Feldelement bestimmen. Wenn zum Beispiel nach dem Namen des dritten Läufers gefragt wird, so lautet die Antwort:
Name = Läufer(3).
Sequentiell suchen heisst hintereinander jedes Element mit einem Suchwert vergleichen, bis die Suche Erfolg hat. Wenn zum Beispiel nach der Nummer der Läuferin Dora gefragt wird, so lautet die Antwort: Vergleiche der Reihe nach alle Elemente, bis die Nummer gefunden wird:
For Nummer = 1 To 5 If Läufer(Nummer) = “Dora” Then MsgBox “Nummer von Dora = ” & Nummer Exit For End If Next Nummer
Die Zählschleife geht solange von Zelle zu Zelle, bis der Inhalt des laufenden Elements mit Dora übereinstimmt. Dann wird in einem Ausgabefeld Nummer von Dora = und die gefundene Nummer ausgegeben (& verknüpft zwei Zeichenketten und konvertiert dabei die Zahl Nummer automatisch in einen String). Weil die Suche nun beendet ist, verlässt die Anweisung Exit For die Zählschleife. Damit lässt sich die Syntax der Zählschleife wie folgt erweitern:
Dim Index As Integer
For Index = <Untergrenze> To <Obergrenze>
<Anweisungen>
[Exit For]
<Anweisungen>]
Next Index
Exit For steht in eckigen Klammern, weil es weggelassen werden kann, falls die Schleife nicht mitten im Schleifenkörper verlassen werden muss.
Wer im Telefonbuch sucht, ...
Eine solche Suche heisst Binärsuche. Sie halbiert ein sortiertes Datenfeld solange, bis das gesuchte Element gefunden wird. Bevor wir eine VBA-Prozedur implementieren, beschreiben wir die Binärsuche entwurfssprachlich. Wir stellen dazu den Suchalgorithmus an unserem Läuferbeispiel und dem Beispielaufruf sucheBinär(1, 7, 'Paul', 4) dar. Das erste Argument enthält die Untergrenze 1 des zu durchsuchenden Feldbereichs. Beim ersten Aufruf von sucheBinär ist der zu durchsuchende Feldbereich identisch mit dem ganzen Datenfeld Läufer. Spätere Aufrufe durchsuchen nur noch einen Teil des Datenfelds. Das zweite Argument nennt die Obergrenze des Feldbereichs - beim ersten Aufruf ist dies 7. Das dritte Argument entspricht dem Suchwert - in unserem Beispiel Paul -, und das vierte Argument nennt die Mitte des Feldbereichs. Vor dem ersten Aufruf ist die Mitte (1 + 7) / 2 = 4. Spätere Aufrufe gehen von einer neu berechneten Mitte aus.
Die folgende Tabelle erweitert unser Läuferbeispiel um die Zellen 6 und 7 und erlaubt in den letzten drei Zeilen die Verfolgung der binären Suche:
|
Nr |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
Läufer(Nr) |
ANNA |
BRUNO |
DORA |
FRANZ |
KARIN |
NORA |
PAUL |
|
1. Schritt |
L |
|
|
M |
|
|
R |
|
2. Schritt |
|
|
|
|
L |
M |
R |
|
3. Schritt |
|
|
|
|
|
|
L, M, R |
Links Index der Untergrenze des betrachteten Feldbereichs
Mitte
Index der
Mitte des betrachteten Feldbereichs
Rechts Index der Obergrenze des betrachteten
Feldbereichs
Gesucht sei die Startnummer des Läufers Paul. Aus der Tabelle erkennen wir sofort als Suchergebnis 7. Weil der Computer nicht über die menschliche Fähigkeit des unmittelbaren Erkennens von Mustern verfügt, müssen wir ihm den Algorithmus der Binärsuche schrittweise beibringen. Im ersten Schritt ermittelt der Algorithmus aus den Positionsindizes Links und Rechts den Index Mitte. Weil der Läufer auf der Position Mitte (Franz) nicht gleich Paul ist, sucht der Algorithmus weiter. Der Name Paul ist alphabetisch grösser als Franz. Deshalb wird der rechte Teil des Datenfelds weiter untersucht: Die neue Mitte berechnet sich wieder aus Links und Rechts. Die Läufern an der neuen Position Mitte heisst Nora und ist ebenfalls kleiner als Paul. Weil jetzt der rechte Teil des Datenfelds nur noch aus einer einzigen Zelle besteht, fallen die Positionen Links, Rechts und Mitte zusammen, und der Läufer an der Position Mitte entspricht dem Suchwert Paul.
Dieser verbalen Beschreibung der Binärsuche entspricht der folgende entwurfssprachliche Algorithmus. Die obige Beispielsuche entspricht dem Aufruf sucheBinär(1, 7, 'Paul', 4).
sucheBinär(links,rechts, Name, Mitte) Mitte = (links + rechts) \ 2 ‘ ganzzahlige Division Falls links <= Mitte dann Falls Name = Feld(Mitte) dann Name gefunden sonst Falls Name < Feld(Mitte) dann sucheBinär(links, Mitte-1, Name, Mitte) sonst Name > Feld(Mitte) sucheBinär(Mitte+1, rechts, Name, Mitte) sonst Name nicht gefunden
Der Rückwärtsstrich-Operator \ dividiert ganzzahlig. Zum Beispiel ergibt 5 \ 2 statt der Gleitkommazahl 2.5 die Ganzahl 2. Der Algorithmus ruft sich je nach Bedingung mit einer der fett gedruckten Anweisungen selbst wieder auf. Er heisst deshalb rekursiv (von lat. recurrere = zurücklaufen). Die folgende Geschichte veranschaulicht den Grundgedanken der Rekursion:
Ein Hund kam in die Küche und stahl dem Koch ein Ei,
da nahm der Koch den Löffel und schlug den Hund entzwei,
da kamen viele Hunde und gruben ihm ein Grab und setzten ihm einen Grabstein, worauf geschrieben stand:
Ein Hund kam in die Küche und stahl dem Koch ein Ei,
da nahm der Koch den Löffel und schlug den Hund entzwei,
da kamen viele Hunde und gruben ihm ein Grab und setzten ihm einen Grabstein, worauf geschrieben stand:
...
Diese Geschichte ist unendlich rekursiv, weil sie sich selbst aufruft, indem sie auf die vorangehende Geschichte zurückspringt. Die Katze beisst sich also in den Schwanz. Im Gegensatz zur Hundegeschichte ist sucheBinär endlich rekursiv. Ein endlich rekursives Programm ruft sich nur solange auf, bis eine Endbedingung erfüllt wird. In unserem Fall soll der Name an der Position Mitte gleich dem gesuchten Namen ein.
Wenn Sie auf den Startknopf von sucheBinär.xls drücken, erscheint ein Eingabefeld, das Sie auffordert, einen Suchnamen - zum Beispiel NORA - einzugeben (siehe Bild unten). Die gefundene Zellnummer wird dann in einem Ausgabefeld angezeigt. Andernfalls erscheint die Fehlermeldung Kein Element mit diesem Wert. Ereignisprozedur der Schaltfläche Suche binär ist die Subroutine sucheBinär() (siehe Programmausschnitt unten).
Damit das Datenfeld Läufer sowohl in der Subroutine sucheBinär() als auch in der aufgerufenden Funktion gefunden gelesen werden kann, vereinbaren wir Läufer als globale Variable:
Private Läufer(1 To 7) As String ‘globale Variable
Leserlicher und sicherer wäre eine Vereinbarung von Läufer in der Subroutine sucheBinär() und eine Übergabe des Datenfelds an die Funktion gefunden:
If gefunden(Läufer, 1,7, Suchname, Nr) = True Then ...
Datenfelder können aber nur in der neuesten Version von Visual Basic Argumente von Prozeduren sein. Das Datenfeld Läufer vereinbaren wir deshalb als globale Variable (die in allen Prozeduren gelesen und verändert werden könnte):
gefunden(links,
rechts, Läufername, Mitte) ist eine boolsche Funktion,
welche die entwurfssprachliche Version der Binärsuche implementiert. Sie
ergibt True, falls der Suchname im Datenfeld vorkommt. Die Nummer der gefundenen
Zelle wird als Argument
Mitte zurückgegeben (letzter Programmausschnitt
unten).
Sub sucheBinaer() Dim Nr As Integer, Suchname As String Läufer(1) = “ANNA” Läufer(2) = “BRUNO” Läufer(3) = “DORA” Läufer(4) = “FRANZ” Läufer(5) = “KARIN” Läufer(6) = “NORA” Läufer(7) = “PAUL” Suchname = InputBox(“Name in Grossbuchstaben: ”) If gefunden(1,7, Suchname, Nr) = True Then MsgBox “Gesuchte Nummer = ” & Nr ElseIf Suchname <> “” ‘ kein Klick auf “Abbrechen” MsgBox “Kein Element mit diesem Wert” End If End Sub
Ereignisprozedur der Schaltfläche ‘Suche binär’
Function gefunden( _ links As Integer, _ rechts As Integer, _ Läufername As String, _ Mitte As Integer) As Boolean ‘ Mitte gibt die gefundene Läufernummer zurück Mitte = (links + rechts) \ 2 If links <= Mitte Then If Läufername = Läufer(Mitte) Then gefunden = True Else If Läufername < Läufer(Mitte) Then gefunden = gefunden(links, Mitte-1, Läufername, Mitte) Else gefunden = gefunden(Mitte+1, rechts, Läufername, Mitte) Else gefunden = False End If End Function
Binärsuche als VBA-Funktion